﻿// -----------------------------------------------------------------------
// <copyright file="DirectoryWebflowCatalog.cs" company="Sławomir Rosiek">
//     Copyright (c) Sławomir Rosiek. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

namespace Rosieks.Web.Flow
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading;
    using System.Web.Mvc;
    using Rosieks.Web.Flow.Internals;
    using Rosieks.Web.Flow.Metadata;

    public class DirectoryWebflowCatalog : IWebflowCatalog
    {
        private readonly FileSystemWatcher watcher = new FileSystemWatcher();
        private readonly Dictionary<string, WebflowModel> models = new Dictionary<string, WebflowModel>();
        private readonly ReaderWriterLockSlim modelsLock = new ReaderWriterLockSlim();
        private readonly string lookupDirectory;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:DirectoryWebflowCatalog"/> class.
        /// </summary>
        public DirectoryWebflowCatalog()
        {
            this.lookupDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Webflows");
            this.watcher.Changed += (s, e) => this.Remove(e.Name);
            this.watcher.Renamed += (s, e) => this.Remove(e.OldName);
            this.watcher.Deleted += (s, e) => this.Remove(e.Name);
            this.watcher.Path = this.lookupDirectory;
            this.watcher.EnableRaisingEvents = true;
        }

        public WebflowModel Load(string name)
        {
            using (this.modelsLock.BeginEnterUpgradeableReadLock())
            {
                WebflowModel model;
                if (!this.models.TryGetValue(name, out model))
                {
                    model = this.LoadFromFile(name);
                }

                return model;
            }
        }

        private WebflowModel LoadFromFile(string name)
        {
            using (this.modelsLock.BeginEnterWriteLock())
            {
                string path = Path.Combine(this.lookupDirectory, name + ".webflow");

                FileInfo file = new FileInfo(path);
                if (file.Exists)
                {
                    using (var stream = file.OpenRead())
                    {
                        var deserializer = new WebflowDeserializer();

                        var model = deserializer.Deserialize(stream);

                        this.models.Add(name, model);

                        return model;
                    }
                }
                else
                {
                    // TODO: Dodać treść komunikatu.
                    throw new ArgumentException(string.Format("No such file: '{0}'", path));
                }
            }
        }

        private void Remove(string name)
        {
            using (this.modelsLock.BeginEnterWriteLock())
            {
                this.models.Remove(name);
            }
        }
    }
}
